package main

// import (
// 	"bufio"
// 	"fmt"
// 	"io"
// 	"net/http"
// 	"os"
// 	"regexp"
// 	"strings"
// 	"sync"
// 	"time"

// 	"golang.org/x/net/html"
// )

// // 曲目信息结构体
// type Track struct {
// 	Name string // 曲目名称
// 	URL  string // 完整播放URL
// }

// // 发送HTTP请求，获取网页内容（带简单反爬策略）
// func fetchHTML(url string) (string, error) {
// 	client := &http.Client{
// 		Timeout: 10 * time.Second,
// 	}
// 	req, err := http.NewRequest("GET", url, nil)
// 	if err != nil {
// 		return "", fmt.Errorf("创建请求失败: %v", err)
// 	}

// 	// 设置User-Agent，模拟浏览器请求（避免被拦截）
// 	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")

// 	resp, err := client.Do(req)
// 	if err != nil {
// 		return "", fmt.Errorf("请求失败: %v", err)
// 	}
// 	defer resp.Body.Close()

// 	if resp.StatusCode != http.StatusOK {
// 		return "", fmt.Errorf("请求失败，状态码: %d", resp.StatusCode)
// 	}

// 	body, err := io.ReadAll(resp.Body)
// 	if err != nil {
// 		return "", fmt.Errorf("读取响应失败: %v", err)
// 	}

// 	return string(body), nil
// }

// // 解析HTML，提取单页中的所有曲目（名称+MP3 ID）
// func parseTracks(htmlContent string) ([]Track, error) {
// 	doc, err := html.Parse(strings.NewReader(htmlContent))
// 	if err != nil {
// 		return nil, fmt.Errorf("解析HTML失败: %v", err)
// 	}

// 	var tracks []Track
// 	// 递归遍历HTML节点，寻找曲目信息
// 	var traverse func(*html.Node)
// 	traverse = func(n *html.Node) {
// 		if n.Type == html.ElementNode && n.Data == "div" {
// 			// 查找包含曲目信息的容器（根据Chillhop网页结构）
// 			for _, attr := range n.Attr {
// 				if attr.Key == "class" && strings.Contains(attr.Val, "track-item") {
// 					// 提取曲目名称
// 					var trackName string
// 					var nameNode *html.Node
// 					// 查找名称节点（假设名称在class为"track-title"的元素中）
// 					findNodeWithClass(n, "track-title", &nameNode)
// 					if nameNode != nil && nameNode.FirstChild != nil {
// 						trackName = strings.TrimSpace(nameNode.FirstChild.Data)
// 					}

// 					// 提取MP3 ID（从播放按钮的链接中提取）
// 					var mp3ID string
// 					var playButton *html.Node
// 					findNodeWithClass(n, "play-button", &playButton)
// 					if playButton != nil {
// 						// 假设播放按钮的"data-track-id"属性是MP3 ID
// 						for _, attr := range playButton.Attr {
// 							if attr.Key == "data-track-id" {
// 								mp3ID = attr.Val
// 								break
// 							}
// 						}
// 					}

// 					// 拼接完整URL（按你的示例格式）
// 					if trackName != "" && mp3ID != "" {
// 						fullURL := fmt.Sprintf("https://get.2sb.org/https://stream.chillhop.com/mp3/%s", mp3ID)
// 						tracks = append(tracks, Track{
// 							Name: trackName,
// 							URL:  fullURL,
// 						})
// 					}
// 					break
// 				}
// 			}
// 		}

// 		// 递归处理子节点
// 		for c := n.FirstChild; c != nil; c = c.NextSibling {
// 			traverse(c)
// 		}
// 	}

// 	traverse(doc)
// 	return tracks, nil
// }

// // 辅助函数：在节点中查找包含指定class的子节点
// func findNodeWithClass(parent *html.Node, className string, result **html.Node) {
// 	var traverse func(*html.Node)
// 	traverse = func(n *html.Node) {
// 		if n.Type == html.ElementNode {
// 			for _, attr := range n.Attr {
// 				if attr.Key == "class" && strings.Contains(attr.Val, className) {
// 					*result = n
// 					return
// 				}
// 			}
// 		}
// 		for c := n.FirstChild; c != nil; c = c.NextSibling {
// 			traverse(c)
// 			if *result != nil {
// 				return
// 			}
// 		}
// 	}
// 	traverse(parent)
// }

// // 将曲目列表写入文件（格式：名称!URL）
// func saveTracks(tracks []Track, filename string) error {
// 	file, err := os.Create(filename)
// 	if err != nil {
// 		return fmt.Errorf("创建文件失败: %v", err)
// 	}
// 	defer file.Close()

// 	writer := bufio.NewWriter(file)
// 	for _, track := range tracks {
// 		// 处理名称中的特殊字符（避免格式错误）
// 		cleanName := regexp.MustCompile(`[^\w\s\p{L}\-']`).ReplaceAllString(track.Name, "")
// 		line := fmt.Sprintf("%s!%s\n", cleanName, track.URL)
// 		if _, err := writer.WriteString(line); err != nil {
// 			return fmt.Errorf("写入文件失败: %v", err)
// 		}
// 	}
// 	return writer.Flush()
// }

// func main() {
// 	// 要爬取的页面范围（Chillhop的发行页分页）
// 	startPage := 1
// 	endPage := 5 // 爬取1-5页，可根据需要调整

// 	var allTracks []Track
// 	var wg sync.WaitGroup
// 	var mu sync.Mutex // 保护allTracks的并发写入

// 	fmt.Printf("开始爬取 Chillhop 曲目（第%d-%d页）...\n", startPage, endPage)

// 	for page := startPage; page <= endPage; page++ {
// 		wg.Add(1)
// 		go func(page int) {
// 			defer wg.Done()
// 			// 构造分页URL（Chillhop的发行页格式）
// 			url := fmt.Sprintf("https://chillhop.com/releases/?page=%d", page)
// 			fmt.Printf("正在爬取第%d页: %s\n", page, url)

// 			// 抓取并解析页面
// 			htmlContent, err := fetchHTML(url)
// 			if err != nil {
// 				fmt.Printf("第%d页抓取失败: %v\n", page, err)
// 				return
// 			}

// 			tracks, err := parseTracks(htmlContent)
// 			if err != nil {
// 				fmt.Printf("第%d页解析失败: %v\n", page, err)
// 				return
// 			}

// 			// 加锁写入全局列表
// 			mu.Lock()
// 			allTracks = append(allTracks, tracks...)
// 			mu.Unlock()

// 			fmt.Printf("第%d页完成，获取%d首曲目\n", page, len(tracks))
// 			time.Sleep(2 * time.Second) // 延迟2秒，避免请求过于频繁
// 		}(page)
// 	}

// 	wg.Wait() // 等待所有分页爬取完成

// 	// 去重（避免重复曲目）
// 	seen := make(map[string]bool)
// 	var uniqueTracks []Track
// 	for _, track := range allTracks {
// 		if !seen[track.URL] {
// 			seen[track.URL] = true
// 			uniqueTracks = append(uniqueTracks, track)
// 		}
// 	}

// 	// 保存结果
// 	if err := saveTracks(uniqueTracks, "tracks.txt"); err != nil {
// 		fmt.Printf("保存文件失败: %v\n", err)
// 		return
// 	}

// 	fmt.Printf("爬取完成！共获取%d首曲目，已保存到 tracks.txt\n", len(uniqueTracks))
// }
